unit fpguiTerm;

{$mode objfpc}{$H+}



interface

uses
  SysUtils, Classes, Sqlite3DS, sqlite3, fpg_base, fpg_main, fpg_form, fpg_salelistbox,
  fpg_panel, fpg_tab, fpg_button, fpg_label, fpg_edit, fpg_combobox, fpg_imgfmt_bmp,
  fpg_listbox, fpg_splitter, fpg_dialogs, fposclientdb, fposclientcore, fposdialogs,
  fposUtils, fpstructs, fpg_resources, fpg_grid, fpg_scrollbar, fpg_widget, md5, basereports;


type

  { TProductButton }

  TProductButton = class(TfpgButton)
  private
    fProductInfo: TfpProduct;
  public
    constructor Create(AOwner: TComponent); override;
    property Product: TfpProduct read fProductInfo write fProductInfo;
  end;


  TButtonlist = array of array of TProductButton;

  {TProductPage}

  TProductPage = class(TfpgTabSheet)
  private
    fCols: integer;
    fRows: integer;
    procedure DeleteButtons;
  public
    ButtonList: TButtonlist;
    procedure BeforeDestruction; override;
    procedure CreateButtons(cols, rows: integer; ClickEvent: TNotifyEvent);
    procedure AlignButtons;
  end;


  { TfposTerm }

  TfposTerm = class(TfpgForm)
  private
    {@VFD_HEAD_BEGIN: fposTerm}
    StatusPanel: TfpgPanel;
    ConnectionStatusLabel: TfpgLabel;
    StaffNameLabel: TfpgLabel;
    TopPanel: TfpgPanel;
    DateTimePanel: TfpgPanel;
    DayLabel: TfpgLabel;
    MonthLabel: TfpgLabel;
    TimeLabel: TfpgLabel;
    DateLabel: TfpgLabel;
    Bevel1: TfpgBevel;
    MainInputPanel: TfpgPanel;
    LowerPanel: TfpgPanel;
    TotalButton: TfpgButton;
    ReceiptButton: TfpgButton;
    Panel6: TfpgPanel;
    SaleModePanel: TfpgPanel;
    BarcodeSaleButton: TfpgButton;
    ManualsaleButton: TfpgButton;
    MenuButton: TfpgButton;
    SaleInputPanel: TfpgPanel;
    PageControl: TfpgPageControl;
    SaleInfoPanel: TfpgPanel;
    SaleAdjustmentPanel: TfpgPanel;
    IncreaseSaleButton: TfpgButton;
    DecreaseSaleButton: TfpgButton;
    SaleSummaryPanel: TfpgPanel;
    TotalLabel: TfpgLabel;
    Label2: TfpgLabel;
    ItemsLabel: TfpgLabel;
    SaleStatusLabel: TfpgLabel;
    SaleNumLabel: TfpgLabel;
    SaleListbox: TfpgSaleListbox;
    Button1: TfpgButton;
    QuantityLabel: TfpgLabel;
    {@VFD_HEAD_END: fposTerm}
    fbarcodebuffer: string;
    freadingbarcode: Boolean;
    //fRefund: Boolean;
    Logo: TfpgImage;
    fClockTimer: TfpgTimer;
    procedure OnFormResize(Sender: TObject);
    procedure OnClockTimer(Sender: TObject);
    procedure SetDateDay;
    procedure ProductButtonClick(Sender: TObject);
    procedure ManualSaleButtonClick(Sender: TObject);
    procedure IncreaseSaleClick(Sender: TObject);
    procedure DecreaseSaleClick(Sender: TObject);
    procedure TotalButtonClick(Sender: TObject);
    procedure PaintLogo(Sender: TObject);
    procedure UpdateTotal;
    procedure Keypress(Sender: TObject; var KeyCode: word; var ShiftState: TShiftState; var Consumed: boolean);
    procedure HandleDisconnect ( aSocket: TObject ) ;
    procedure HandleConnect ( aSocket: TObject ) ;
    procedure AddSaleByBarcode( abarcode: Pchar=nil );
    procedure ModeButtonClick(Sender: TObject);
    procedure ReceiptButtonClick(Sender: TObject);
    procedure BarcodeEnterClick(Sender: TObject);
    procedure ResumeShift(Sender: TObject);
    procedure StaffStatusChange(Sender: TObject; SQL: string);
    procedure MenuButtonClick(Sender: TObject);
    procedure ButtonPagesResize(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure SetSaleQuantity(Sender: TObject);
    procedure ResetSaleQuantity( value: integer=1 );
    procedure RefreshDiscounts;
    function  GetScreenPos( Widget: tfpgWidget): TPoint;
    procedure DisplayMessage( msg: string );
    procedure DisplayTotal(Sender: TObject);
    procedure UpdateLock;
  public
    SaleTotal: single;
    procedure AfterCreate; override;
    procedure BeforeDestruction; override;
    procedure RefundClick(Sender: TObject);
    procedure CancelSaleClick(Sender: TObject);
    procedure CreatePage(pagetitle: string);
    procedure SetupPages;
    procedure SetupButtons;
    procedure EndShift;
  end;



  { TFindItemForm }

  TFindItemForm = class(TfpgForm)
  private
    {@VFD_HEAD_BEGIN: FindItemForm}
    BarcodePanel: TfpgPanel;
    BarcodeEntryEdit: TfpgEdit;
    Label1: TfpgLabel;
    BarcodeProdnameLabel: TfpgLabel;
    BarcodePriceLabel: TfpgLabel;
    BarcodeEnterButton: TfpgButton;
    BarcodeClearButton: TfpgButton;
    ProductLookupGrid: TfpgStringGrid;
    CloseButton: TfpgButton;
    TitleLabel: TfpgLabel;
    {@VFD_HEAD_END: FindItemForm}
    procedure BarcodeEditChange(Sender: TObject);
    procedure ResetBarcodePanel(Sender: TObject);
    procedure CloseWindow(Sender: TObject);
    procedure SelectItem(Sender: TObject);
    procedure Keypress(Sender: TObject; var KeyCode: word; var ShiftState: TShiftState; var Consumed: boolean);
  public
    procedure AfterCreate; override;
  end;

  { TManualEntryForm }

  TManualEntryForm = class(TfpgForm)
  private
    {@VFD_HEAD_BEGIN: ManualEntryForm}
    KeypadPanel: TfpgPanel;
    Pad7Button: TfpgButton;
    Pad8Button: TfpgButton;
    Pad9Button: TfpgButton;
    Pad4Button: TfpgButton;
    Pad5Button: TfpgButton;
    Pad6Button: TfpgButton;
    Pad1Button: TfpgButton;
    Pad2Button: TfpgButton;
    Pad3Button: TfpgButton;
    Pad0Button: TfpgButton;
    PadDecButton: TfpgButton;
    ManualEnterButton: TfpgButton;
    DeleteButton: TfpgButton;
    Label3: TfpgLabel;
    DepartmentComboBox: TfpgComboBox;
    EditFloat1: TfpgEditFloat;
    Label4: TfpgLabel;
    CloseManualButton: TfpgButton;
    EditQuantity: TfpgEditInteger;
    QtyIncButton: TfpgButton;
    QtyDecButton: TfpgButton;
    Label1: TfpgLabel;
    TitleLabel: TfpgLabel;
    {@VFD_HEAD_END: ManualEntryForm}
    procedure DeleteButtonClick(Sender: TObject);
    procedure NumPadButtonClick(Sender: TObject);
    procedure CloseWindow(Sender: TObject);
    procedure ChangeQuantity(Sender: TObject);
  public
    procedure AfterCreate; override;
  end;

  { TSetQuantityForm }

  TSetQuantityForm = class(TfpgForm)
  private
    {@VFD_HEAD_BEGIN: SetQuantityForm}
    KeypadPanel: TfpgPanel;
    Pad7Button: TfpgButton;
    Pad8Button: TfpgButton;
    Pad9Button: TfpgButton;
    Pad4Button: TfpgButton;
    Pad5Button: TfpgButton;
    Pad6Button: TfpgButton;
    Pad1Button: TfpgButton;
    Pad2Button: TfpgButton;
    Pad3Button: TfpgButton;
    Pad0Button: TfpgButton;
    PadDecButton: TfpgButton;
    ManualEnterButton: TfpgButton;
    DeleteButton: TfpgButton;
    EditQuantity: TfpgEditInteger;
    QtyIncButton: TfpgButton;
    QtyDecButton: TfpgButton;
    OKButton: TfpgButton;
    CancelButton: TfpgButton;
    TitleLabel: TfpgLabel;
    {@VFD_HEAD_END: SetQuantityForm}
    procedure DeleteButtonClick(Sender: TObject);
    procedure NumPadButtonClick(Sender: TObject);
    procedure ChangeQuantity(Sender: TObject);
    procedure DoQuantityChanged(Sender: TObject);
    procedure CloseButtonClick(Sender: TObject);
    procedure Keypress(Sender: TObject; var KeyCode: word; var ShiftState: TShiftState; var Consumed: boolean);
  public
    procedure AfterCreate; override;
  end;

{@VFD_NEWFORM_DECL}
const
  BUTTONMARGIN = 10;   //space between buttons
  MIN_LOOKUP_LENGTH = 3;

var
  fposTerm: TfposTerm;
  ManualEntryForm: TManualEntryForm;
  FindItemForm: TFindItemForm;
  SetQuantityForm: TSetQuantityForm;



implementation

uses StarSerial;


{ TProductButton }

constructor TProductButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  AllowMultiLineText := true;
  BackgroundColor := clWhiteSmoke;
end;

{@VFD_NEWFORM_IMPL}

procedure TSetQuantityForm.DeleteButtonClick ( Sender: TObject ) ;
begin

end;

procedure TSetQuantityForm.NumPadButtonClick ( Sender: TObject ) ;
begin
  if EditQuantity.Value=0
      then EditQuantity.Value := StrToInt(TfpgButton(Sender).Text)
  else EditQuantity.Value := (EditQuantity.Value*10) + StrToInt(TfpgButton(Sender).Text);
end;

procedure TSetQuantityForm.ChangeQuantity ( Sender: TObject ) ;
begin
  if Sender=QtyIncButton
     then EditQuantity.Value := EditQuantity.Value+1
     else
       if Sender=QtyDecButton
          then if EditQuantity.Value>1
               then EditQuantity.Value := EditQuantity.Value-1;
end;

procedure TSetQuantityForm.DoQuantityChanged ( Sender: TObject ) ;
begin
  OKButton.Enabled := EditQuantity.Value>0;
end;

procedure TSetQuantityForm.CloseButtonClick ( Sender: TObject ) ;
begin
  ModalResult := TfpgButton(Sender).ModalResult;
  Close;
end;

procedure TSetQuantityForm.Keypress ( Sender: TObject; var KeyCode: word;
  var ShiftState: TShiftState; var Consumed: boolean ) ;
begin
  if KeyCode=keyEscape then CloseButtonClick(Sender);
end;

procedure TSetQuantityForm.AfterCreate;
begin
  {%region 'Auto-generated GUI code' -fold}
  {@VFD_BODY_BEGIN: SetQuantityForm}
  Name := 'SetQuantityForm';
  SetPosition(253, 268, 431, 534);
  WindowTitle := 'SetQuantityForm';
  Hint := '';
  WindowAttributes := [waBorderless];
  OnKeyPress := @Keypress;

  KeypadPanel := TfpgPanel.Create(self);
  with KeypadPanel do
  begin
    Name := 'KeypadPanel';
    SetPosition(0, 0, 431, 534);
    Anchors := [anLeft,anRight,anTop,anBottom];
    Align := alClient;
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Label1';
    Hint := '';
    Text := '';
  end;

  Pad7Button := TfpgButton.Create(KeypadPanel);
  with Pad7Button do
  begin
    Name := 'Pad7Button';
    SetPosition(166, 92, 70, 70);
    Anchors := [anRight,anTop];
    Text := '7';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 1;
    OnClick := @NumPadButtonClick;
  end;

  Pad8Button := TfpgButton.Create(KeypadPanel);
  with Pad8Button do
  begin
    Name := 'Pad8Button';
    SetPosition(248, 92, 70, 70);
    Anchors := [anRight,anTop];
    Text := '8';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 2;
    OnClick := @NumPadButtonClick;
  end;

  Pad9Button := TfpgButton.Create(KeypadPanel);
  with Pad9Button do
  begin
    Name := 'Pad9Button';
    SetPosition(330, 92, 70, 70);
    Anchors := [anRight,anTop];
    Text := '9';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 3;
    OnClick := @NumPadButtonClick;
  end;

  Pad4Button := TfpgButton.Create(KeypadPanel);
  with Pad4Button do
  begin
    Name := 'Pad4Button';
    SetPosition(166, 170, 70, 70);
    Anchors := [anRight,anTop];
    Text := '4';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 4;
    OnClick := @NumPadButtonClick;
  end;

  Pad5Button := TfpgButton.Create(KeypadPanel);
  with Pad5Button do
  begin
    Name := 'Pad5Button';
    SetPosition(248, 170, 70, 70);
    Anchors := [anRight,anTop];
    Text := '5';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 5;
    OnClick := @NumPadButtonClick;
  end;

  Pad6Button := TfpgButton.Create(KeypadPanel);
  with Pad6Button do
  begin
    Name := 'Pad6Button';
    SetPosition(330, 170, 70, 70);
    Anchors := [anRight,anTop];
    Text := '6';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 6;
    OnClick := @NumPadButtonClick;
  end;

  Pad1Button := TfpgButton.Create(KeypadPanel);
  with Pad1Button do
  begin
    Name := 'Pad1Button';
    SetPosition(166, 252, 70, 70);
    Anchors := [anRight,anTop];
    Text := '1';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 7;
    OnClick := @NumPadButtonClick;
  end;

  Pad2Button := TfpgButton.Create(KeypadPanel);
  with Pad2Button do
  begin
    Name := 'Pad2Button';
    SetPosition(248, 252, 70, 70);
    Anchors := [anRight,anTop];
    Text := '2';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 8;
    OnClick := @NumPadButtonClick;
  end;

  Pad3Button := TfpgButton.Create(KeypadPanel);
  with Pad3Button do
  begin
    Name := 'Pad3Button';
    SetPosition(330, 252, 70, 70);
    Anchors := [anRight,anTop];
    Text := '3';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 9;
    OnClick := @NumPadButtonClick;
  end;

  Pad0Button := TfpgButton.Create(KeypadPanel);
  with Pad0Button do
  begin
    Name := 'Pad0Button';
    SetPosition(248, 334, 70, 70);
    Anchors := [anRight,anTop];
    Text := '0';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 10;
    OnClick := @NumPadButtonClick;
  end;

  PadDecButton := TfpgButton.Create(KeypadPanel);
  with PadDecButton do
  begin
    Name := 'PadDecButton';
    SetPosition(330, 334, 70, 70);
    Anchors := [anRight,anTop];
    Text := '.';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 11;
    OnClick := @NumPadButtonClick;
    //   Visible := false;
    // Probably not required
  end;

  ManualEnterButton := TfpgButton.Create(KeypadPanel);
  with ManualEnterButton do
  begin
    Name := 'ManualEnterButton';
    SetPosition(518, 40, 124, 70);
    Anchors := [anRight,anTop];
    Text := 'Enter';
    Enabled := False;
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 12;
    OnClick := @fposTerm.ManualSaleButtonClick;
  end;

  DeleteButton := TfpgButton.Create(KeypadPanel);
  with DeleteButton do
  begin
    Name := 'DeleteButton';
    SetPosition(166, 334, 70, 70);
    Anchors := [anRight,anTop];
    Text := 'Delete';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 13;
    OnClick := @DeleteButtonClick;
  end;

  EditQuantity := TfpgEditInteger.Create(KeypadPanel);
  with EditQuantity do
  begin
    Name := 'EditQuantity';
    SetPosition(48, 96, 56, 40);
    FontDesc := '#LargeText';
    Hint := '';
    ParentShowHint := False;
    ShowHint := True;
    TabOrder := 19;
    Value := 1;
    OnChange := @DoQuantityChanged;
  end;

  QtyIncButton := TfpgButton.Create(KeypadPanel);
  with QtyIncButton do
  begin
    Name := 'QtyIncButton';
    SetPosition(48, 152, 60, 60);
    Text := '+';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 20;
    OnClick := @ChangeQuantity;
  end;

  QtyDecButton := TfpgButton.Create(KeypadPanel);
  with QtyDecButton do
  begin
    Name := 'QtyDecButton';
    SetPosition(48, 224, 60, 59);
    Text := '-';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 21;
    OnClick := @ChangeQuantity;
  end;

  OKButton := TfpgButton.Create(KeypadPanel);
  with OKButton do
  begin
    Name := 'OKButton';
    SetPosition(336, 456, 80, 68);
    Text := 'OK';
    BackgroundColor := TfpgColor($32CD32);
    Enabled := False;
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    ModalResult := mrOK;
    TabOrder := 17;
    Onclick := @CloseButtonClick;
  end;

  CancelButton := TfpgButton.Create(KeypadPanel);
  with CancelButton do
  begin
    Name := 'CancelButton';
    SetPosition(8, 460, 80, 68);
    Text := 'Cancel';
    BackgroundColor := TfpgColor($FF0000);
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    ModalResult := mrCancel;
    TabOrder := 18;
    Onclick := @CloseButtonClick;
  end;

  TitleLabel := TfpgLabel.Create(KeypadPanel);
  with TitleLabel do
  begin
    Name := 'TitleLabel';
    SetPosition(156, 20, 212, 36);
    Alignment := taCenter;
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Largetext';
    Hint := '';
    Text := 'Set Quantity';
  end;

  {@VFD_BODY_END: SetQuantityForm}
  {%endregion}
end;


procedure TFindItemForm.BarcodeEditChange ( Sender: TObject ) ;
var
  r: Integer;
  c: Integer;
begin
   ProductLookupGrid.Visible := false;
   BarcodeEnterButton.Enabled := false;
   ProductLookupGrid.FocusRow := -1;
   if Length(BarcodeEntryEdit.Text)=0 then
      begin
          BarcodeProdnameLabel.Visible := false;
          BarcodePriceLabel.Visible := false;
      end;
   if Length(BarcodeEntryEdit.Text)<MIN_LOOKUP_LENGTH then Exit ;
   If (BarcodeEntryEdit.Text[1]='2') and (Length(BarcodeEntryEdit.Text)>7) then
      begin
        BarcodeEnterButton.Enabled := Length(BarcodeEntryEdit.Text)=13;
        if Length(BarcodeEntryEdit.Text)>11 then
           BarcodePriceLabel.Text := FormatFloat(CurrencyFormatString, StrToInt( Copy(BarcodeEntryEdit.Text, 8, 5) ) / 100);
        Exit;
      end;
   r := 0;
   if ClientDB.SearchForProduct(TfpgEdit(Sender).Text, false, true)>0 then
      begin
        ProductLookupGrid.RowCount := ClientDB.DataDB.RecordCount+r;
        While not ClientDB.DataDB.EOF do
              begin
                for c := 0 to 1 do
                    ProductLookupGrid.Cells[c, r] := ClientDB.DataDB.Fields[c+1].AsString;
                ProductLookupGrid.Cells[2, r] := FormatFloat(CurrencyFormatString, ClientDB.DataDB.Fields[3].AsFloat);
                if ProductLookupGrid.Canvas.Font.TextWidth(ClientDB.DataDB.Fields[1].AsString)
                                                                   > ProductLookupGrid.ColumnWidth[0]
                   then ProductLookupGrid.ColumnWidth[0] := ProductLookupGrid.Canvas.Font.TextWidth(ClientDB.DataDB.Fields[1].AsString) + 6;
                ClientDB.DataDB.Next;
                Inc(r);
              end;
        ProductLookupGrid.ColumnWidth[1] :=ProductLookupGrid.Width-ProductLookupGrid.ColumnWidth[0]-ProductLookupGrid.ColumnWidth[2]-4;
        if ProductLookupGrid.RowCount<15 then ProductLookupGrid.Height := ProductLookupGrid.RowCount*ProductLookupGrid.DefaultRowHeight+4;
        ProductLookupGrid.Visible := true;
        if BarcodeEntryEdit.Text=ProductLookupGrid.Cells[0,0] then
           begin
             ProductLookupGrid.SetFocus;
             ProductLookupGrid.FocusRow := 0;
             SelectItem(ProductLookupGrid);
           end;
      end;
end;

procedure TFindItemForm.ResetBarcodePanel ( Sender: TObject ) ;
begin
  BarcodeEntryEdit.OnChange := nil;
  ProductLookupGrid.OnRowChange := nil;
  BarcodeEnterButton.Enabled := false;
  BarcodeEntryEdit.Text := '';
  BarcodePriceLabel.Visible := false;
  BarcodeProdnameLabel.Visible := false;
  ProductLookupGrid.Visible := false;
  ProductLookupGrid.FocusRow := -1;
  ProductLookupGrid.RowCount := 0;
  ProductLookupGrid.Height := ProductLookupGrid.DefaultRowHeight*15;
  BarcodeEntryEdit.OnChange := @BarcodeEditChange;
end;

procedure TFindItemForm.CloseWindow ( Sender: TObject ) ;
begin
  Close;
end;

procedure TFindItemForm.SelectItem(Sender: TObject);
begin
  ClientDB.DataDB.RecNo := ProductLookupGrid.FocusRow+1;
  {$IFDEF DEBUG}
  writeln('ARow=', ProductLookupGrid.FocusRow);
  {$ENDIF}
  BarcodeEntryEdit.OnChange := nil; // prevent lookup from being triggered again
  BarcodeEntryEdit.Text := ProductLookupGrid.Cells[0, ProductLookupGrid.FocusRow];
  BarcodeProdnameLabel.Text := ProductLookupGrid.Cells[1, ProductLookupGrid.FocusRow];
  if BarcodeEntryEdit.Text[1]<>'2'
     then BarcodePriceLabel.Text := ProductLookupGrid.Cells[2, ProductLookupGrid.FocusRow];
  BarcodeEntryEdit.OnChange := @BarcodeEditChange; // re-enable lookups
  ProductLookupGrid.Visible := false;
  BarcodeProdnameLabel.Visible := true;
  BarcodePriceLabel.Visible := true;
  BarcodeEnterButton.Enabled := true;
end;

procedure TFindItemForm.Keypress ( Sender: TObject; var KeyCode: word;
  var ShiftState: TShiftState; var Consumed: boolean ) ;
begin
  case KeyCode of
       keyEscape:      begin
                         if ProductLookupGrid.Visible then
                            begin
                              BarcodeEntryEdit.SetFocus;
                              ProductLookupGrid.Visible := false;
                            end
                         else if Length(BarcodeEntryEdit.Text)=0
                            then CloseWindow(nil)
                         else ResetBarcodePanel(nil);
                       end;
       66 : if (ssCtrl in ShiftState) then
                       begin
                        //Focus input edit
                        if not BarcodeEntryEdit.Focused
                               then BarcodeEntryEdit.SetFocus;
                        fposTerm.fbarcodebuffer := '';
                        fposTerm.freadingbarcode := true;
                       end;
       keyDown:        begin
                         if BarcodeEntryEdit.Focused
                          then if ProductLookupGrid.Visible then
                             begin
                               ProductLookupGrid.SetFocus;
                               ProductLookupGrid.FocusRow := 0;
                             end;
                       end;
       keyEnter,
       keyPEnter:       begin
                         if ProductLookupGrid.Visible
                            then SelectItem(ProductLookupGrid)
                         else if BarcodeEnterButton.Enabled
                              then fposTerm.BarcodeEnterClick(nil);
                       end;
  end;
end;

procedure TFindItemForm.AfterCreate;
begin
  {%region 'Auto-generated GUI code' -fold}
  {@VFD_BODY_BEGIN: FindItemForm}
  Name := 'FindItemForm';
  SetPosition(229, 215, 613, 549);
  WindowTitle := 'FindItemForm';
  Hint := '';
  WindowAttributes := [waBorderless];
  OnKeyPress := @Keypress;

  BarcodePanel := TfpgPanel.Create(self);
  with BarcodePanel do
  begin
    Name := 'BarcodePanel';
    SetPosition(0, 0, 613, 549);
    Anchors := [anLeft,anRight,anTop,anBottom];
    Align := alClient;
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Label1';
    Hint := '';
    Text := '';
  end;

  BarcodeEntryEdit := TfpgEdit.Create(BarcodePanel);
  with BarcodeEntryEdit do
  begin
    Name := 'BarcodeEntryEdit';
    SetPosition(20, 92, 312, 24);
    ExtraHint := '';
    FontDesc := 'FreeSans-14:antialias=true';
    Hint := '';
    TabOrder := 1;
    Text := '';
    OnChange := @BarcodeEditChange;
  end;

  Label1 := TfpgLabel.Create(BarcodePanel);
  with Label1 do
  begin
    Name := 'Label1';
    SetPosition(20, 60, 300, 20);
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Label1';
    Hint := '';
    Text := 'Enter barcode or item name';
  end;

  BarcodeProdnameLabel := TfpgLabel.Create(BarcodePanel);
  with BarcodeProdnameLabel do
  begin
    Name := 'BarcodeProdnameLabel';
    SetPosition(20, 128, 312, 28);
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := 'FreeSans-14:antialias=true';
    Hint := '';
    Text := '';
  end;

  BarcodePriceLabel := TfpgLabel.Create(BarcodePanel);
  with BarcodePriceLabel do
  begin
    Name := 'BarcodePriceLabel';
    SetPosition(312, 128, 312, 28);
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := 'FreeSans-14:antialias=true';
    Hint := '';
    Text := '';
  end;

  BarcodeEnterButton := TfpgButton.Create(BarcodePanel);
  with BarcodeEnterButton do
  begin
    Name := 'BarcodeEnterButton';
    SetPosition(406, 88, 120, 70);
    Anchors := [anRight,anTop];
    Text := 'Enter';
    Enabled := False;
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 6;
    OnClick := @fposTerm.BarcodeEnterClick;
  end;

  BarcodeClearButton := TfpgButton.Create(BarcodePanel);
  with BarcodeClearButton do
  begin
    Name := 'BarcodeClearButton';
    SetPosition(32, 268, 108, 64);
    Text := 'Clear';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 7;
    OnClick := @ResetBarcodePanel;
  end;

  ProductLookupGrid := TfpgStringGrid.Create(BarcodePanel);
  with ProductLookupGrid do
  begin
    Name := 'ProductLookupGrid';
    SetPosition(20, 116, 548, 344);
    BackgroundColor := TfpgColor($80000002);
    AddColumn('', 100, taLeftJustify);
    AddColumn('', 200, taLeftJustify);
    AddColumn('', 50, taRightJustify);
    FontDesc := 'FreeSans-14:antialias=true';
    HeaderFontDesc := '#GridHeader';
    Hint := '';
    RowCount := 0;
    RowSelect := True;
    ShowHeader := False;
    TabOrder := 5;
    //    OnRowChange := @LookupGridSelect;
    OnClick := @SelectItem;
    Visible := false;
    ScrollBarStyle := ssNone;
  end;

  CloseButton := TfpgButton.Create(BarcodePanel);
  with CloseButton do
  begin
    Name := 'CloseButton';
    SetPosition(516, 460, 92, 84);
    Text := 'X';
    BackgroundColor := TfpgColor($FF0000);
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 8;
    OnClick := @CloseWindow;
  end;

  TitleLabel := TfpgLabel.Create(BarcodePanel);
  with TitleLabel do
  begin
    Name := 'TitleLabel';
    SetPosition(184, 16, 288, 36);
    Alignment := taCenter;
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Largetext';
    Hint := '';
    Text := 'Item Search';
  end;

  {@VFD_BODY_END: FindItemForm}
  {%endregion}
end;

procedure TManualEntryForm.NumPadButtonClick ( Sender: TObject ) ;
var
  temptext: string;
  num: Extended;
begin
   ManualEnterButton.Enabled := true;
   if TfpgButton(Sender).Text='.' then
     begin
       EditFloat1.Value := EditFloat1.Value*100;
       Exit;
     end;
  num := StrToInt(TfpgButton(Sender).Text) / 100;
  if EditFloat1.Value=0
     then EditFloat1.Value := num
     else EditFloat1.Value := (EditFloat1.Value * 10) + num;
end;

procedure TManualEntryForm.DeleteButtonClick ( Sender: TObject ) ;
begin
  if Length(EditFloat1.Text) > 1
       then EditFloat1.Text := Copy(EditFloat1.Text, 1, Length(EditFloat1.Text)-1)
       else EditFloat1.Text := '';
end;

procedure TManualEntryForm.CloseWindow ( Sender: TObject ) ;
begin
  fposTerm.ResetSaleQuantity;
  Close;
end;

procedure TManualEntryForm.ChangeQuantity ( Sender: TObject ) ;
begin
  if Sender=QtyIncButton
     then EditQuantity.Value := EditQuantity.Value+1
     else
       if Sender=QtyDecButton
          then if EditQuantity.Value>1
               then EditQuantity.Value := EditQuantity.Value-1;
  fposTerm.ResetSaleQuantity(EditQuantity.Value);
end;

procedure TManualEntryForm.AfterCreate;
var
  x: Integer;
begin
  {%region 'Auto-generated GUI code' -fold}
  {@VFD_BODY_BEGIN: ManualEntryForm}
  Name := 'ManualEntryForm';
  SetPosition(271, 157, 614, 619);
  WindowTitle := 'ManualEntryForm';
  Hint := '';
  WindowAttributes := [waBorderless];

  KeypadPanel := TfpgPanel.Create(self);
  with KeypadPanel do
  begin
    Name := 'KeypadPanel';
    SetPosition(0, 0, 614, 619);
    Anchors := [anLeft,anRight,anTop,anBottom];
    Align := alClient;
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Label1';
    Hint := '';
    Text := '';
  end;

  Pad7Button := TfpgButton.Create(KeypadPanel);
  with Pad7Button do
  begin
    Name := 'Pad7Button';
    SetPosition(121, 228, 70, 70);
    Anchors := [anRight,anTop];
    Text := '7';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 1;
    OnClick := @NumPadButtonClick;
  end;

  Pad8Button := TfpgButton.Create(KeypadPanel);
  with Pad8Button do
  begin
    Name := 'Pad8Button';
    SetPosition(203, 228, 70, 70);
    Anchors := [anRight,anTop];
    Text := '8';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 2;
    OnClick := @NumPadButtonClick;
  end;

  Pad9Button := TfpgButton.Create(KeypadPanel);
  with Pad9Button do
  begin
    Name := 'Pad9Button';
    SetPosition(285, 228, 70, 70);
    Anchors := [anRight,anTop];
    Text := '9';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 3;
    OnClick := @NumPadButtonClick;
  end;

  Pad4Button := TfpgButton.Create(KeypadPanel);
  with Pad4Button do
  begin
    Name := 'Pad4Button';
    SetPosition(121, 306, 70, 70);
    Anchors := [anRight,anTop];
    Text := '4';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 4;
    OnClick := @NumPadButtonClick;
  end;

  Pad5Button := TfpgButton.Create(KeypadPanel);
  with Pad5Button do
  begin
    Name := 'Pad5Button';
    SetPosition(203, 306, 70, 70);
    Anchors := [anRight,anTop];
    Text := '5';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 5;
    OnClick := @NumPadButtonClick;
  end;

  Pad6Button := TfpgButton.Create(KeypadPanel);
  with Pad6Button do
  begin
    Name := 'Pad6Button';
    SetPosition(285, 306, 70, 70);
    Anchors := [anRight,anTop];
    Text := '6';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 6;
    OnClick := @NumPadButtonClick;
  end;

  Pad1Button := TfpgButton.Create(KeypadPanel);
  with Pad1Button do
  begin
    Name := 'Pad1Button';
    SetPosition(121, 388, 70, 70);
    Anchors := [anRight,anTop];
    Text := '1';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 7;
    OnClick := @NumPadButtonClick;
  end;

  Pad2Button := TfpgButton.Create(KeypadPanel);
  with Pad2Button do
  begin
    Name := 'Pad2Button';
    SetPosition(203, 388, 70, 70);
    Anchors := [anRight,anTop];
    Text := '2';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 8;
    OnClick := @NumPadButtonClick;
  end;

  Pad3Button := TfpgButton.Create(KeypadPanel);
  with Pad3Button do
  begin
    Name := 'Pad3Button';
    SetPosition(285, 388, 70, 70);
    Anchors := [anRight,anTop];
    Text := '3';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 9;
    OnClick := @NumPadButtonClick;
  end;

  Pad0Button := TfpgButton.Create(KeypadPanel);
  with Pad0Button do
  begin
    Name := 'Pad0Button';
    SetPosition(203, 470, 70, 70);
    Anchors := [anRight,anTop];
    Text := '0';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 10;
    OnClick := @NumPadButtonClick;
  end;

  PadDecButton := TfpgButton.Create(KeypadPanel);
  with PadDecButton do
  begin
    Name := 'PadDecButton';
    SetPosition(285, 470, 70, 70);
    Anchors := [anRight,anTop];
    Text := '.';
    FontDesc := 'FreeSans-18:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 11;
    OnClick := @NumPadButtonClick;
    //   Visible := false;
    // Probably not required
  end;

  ManualEnterButton := TfpgButton.Create(KeypadPanel);
  with ManualEnterButton do
  begin
    Name := 'ManualEnterButton';
    SetPosition(405, 148, 124, 70);
    Anchors := [anRight,anTop];
    Text := 'Enter';
    Enabled := False;
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 12;
    OnClick := @fposTerm.ManualSaleButtonClick;
  end;

  DeleteButton := TfpgButton.Create(KeypadPanel);
  with DeleteButton do
  begin
    Name := 'DeleteButton';
    SetPosition(121, 472, 70, 70);
    Anchors := [anRight,anTop];
    Text := 'Delete';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 13;
    OnClick := @DeleteButtonClick;
  end;

  Label3 := TfpgLabel.Create(KeypadPanel);
  with Label3 do
  begin
    Name := 'Label3';
    SetPosition(24, 60, 112, 16);
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Label1';
    Hint := '';
    Text := 'Item description';
  end;

  DepartmentComboBox := TfpgComboBox.Create(KeypadPanel);
  with DepartmentComboBox do
  begin
    Name := 'DepartmentComboBox';
    SetPosition(24, 88, 317, 40);
    Anchors := [anLeft,anRight,anTop];
    ExtraHint := '';
    FontDesc := '#Label1';
    Hint := '';
    FocusItem := -1;
    TabOrder := 15;
    for x := 0 to ClientDB.DepartmentCount-1 do
    Items.Add(ClientDB.Department[x].name);
  end;

  EditFloat1 := TfpgEditFloat.Create(KeypadPanel);
  with EditFloat1 do
  begin
    Name := 'EditFloat1';
    SetPosition(122, 172, 120, 40);
    Decimals := 2;
    FixedDecimals := True;
    FontDesc := '#LargeText';
    Hint := '';
    ShowThousand := False;
    TabOrder := 16;
    Value := 0;
  end;

  Label4 := TfpgLabel.Create(KeypadPanel);
  with Label4 do
  begin
    Name := 'Label4';
    SetPosition(124, 148, 80, 16);
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Label1';
    Hint := '';
    Layout := tlCenter;
    Text := 'Item price';
  end;

  CloseManualButton := TfpgButton.Create(KeypadPanel);
  with CloseManualButton do
  begin
    Name := 'CloseManualButton';
    SetPosition(504, 524, 100, 84);
    Text := 'X';
    BackgroundColor := TfpgColor($FF0000);
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 18;
    OnClick := @CloseWindow;
  end;

  EditQuantity := TfpgEditInteger.Create(KeypadPanel);
  with EditQuantity do
  begin
    Name := 'EditQuantity';
    SetPosition(24, 172, 56, 40);
    FontDesc := '#LargeText';
    Hint := '';
    ParentShowHint := False;
    ShowHint := True;
    TabOrder := 19;
    Value := 1;
  end;

  QtyIncButton := TfpgButton.Create(KeypadPanel);
  with QtyIncButton do
  begin
    Name := 'QtyIncButton';
    SetPosition(20, 224, 60, 60);
    Text := '+';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 20;
    // OnClick := @ChangeQuantity;
  end;

  QtyDecButton := TfpgButton.Create(KeypadPanel);
  with QtyDecButton do
  begin
    Name := 'QtyDecButton';
    SetPosition(20, 300, 60, 59);
    Text := '-';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 21;
    //OnClick := @ChangeQuantity;
  end;

  Label1 := TfpgLabel.Create(KeypadPanel);
  with Label1 do
  begin
    Name := 'Label1';
    SetPosition(24, 148, 96, 15);
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Label1';
    Hint := '';
    Text := 'Quantity';
  end;

  TitleLabel := TfpgLabel.Create(KeypadPanel);
  with TitleLabel do
  begin
    Name := 'TitleLabel';
    SetPosition(146, 18, 612, 28);
    BackgroundColor := TfpgColor($FAFAD2);
    FontDesc := '#Largetext';
    Hint := '';
    Text := 'Enter Item Price';
  end;

  {@VFD_BODY_END: ManualEntryForm}
  {%endregion}
end;


procedure TfposTerm.OnFormResize(Sender: TObject);
begin
 // TotalButton.SetPosition(TotalButton.Parent.Width-TotalButton.Width-5, TotalButton.Top, TotalButton.Width, TotalButton.Height);
end;

procedure TfposTerm.OnClockTimer(Sender: TObject);
begin
  TimeLabel.Text := FormatDateTime('hh:mm', Time);
  if TimeLabel.Text = '00:00' then SetDateDay;
  UpdateLock;
  fposClient.CheckConnection;
  //fposClient.Connection.CallAction;
end;

procedure TfposTerm.SetDateDay;
begin
  DayLabel.Text := FormatDateTime('dddd', Date);
  DateLabel.Text := FormatDateTime('d', Date);
  MonthLabel.Text := FormatDateTime('mmm yyyy', Date);
  OnClockTimer(nil);
end;

procedure TfposTerm.BeforeDestruction;
var
  X: Integer;
begin
  For X := 0 to PageControl.PageCount-1 do
      TProductPage(PageControl.Pages[X]).Free;
  inherited BeforeDestruction;
end;

procedure TfposTerm.ProductButtonClick ( Sender: TObject ) ;
var
  SaleItem: TSaleLine;
  x: LongInt;
begin
  if not TotalButton.Enabled then SaleListbox.ResetSale;
  SaleListbox.AddItem(TProductButton(Sender).Product, SetQuantityForm.EditQuantity.Value);
  ResetSaleQuantity;
  DisplayMessage(Copy(TProductButton(Sender).Product.name, 1, 19) + #10#13 + FormatFloat(CurrencyFormatString, TProductButton(Sender).Product.saleprice));
  if not SaleListbox.isRefund then SaleStatusLabel.Text := 'Sale in progress';
  TotalButton.Enabled := SaleListBox.Count>0;
  UpdateTotal;
end;

procedure TfposTerm.ManualSaleButtonClick ( Sender: TObject ) ;
var
  SaleItem: TfpProduct;
begin
  if not TotalButton.Enabled then SaleListbox.ResetSale;
  if ManualEntryForm.DepartmentComboBox.FocusItem <0 then
     begin
       ShowMessage('Please select a sales department');
       ManualEntryForm.DepartmentComboBox.SetFocus;
     end
  else
      begin
        with SaleItem do
             begin
               id := 0-ClientDB.Department[ManualEntryForm.DepartmentComboBox.FocusItem].id;
               barcode := '';
               name := ManualEntryForm.DepartmentComboBox.Text;
               if SaleListbox.isRefund
                  then saleprice := 0 - ManualEntryForm.EditFloat1.Value
               else saleprice := ManualEntryForm.EditFloat1.Value;
               dept := ClientDB.Department[ManualEntryForm.DepartmentComboBox.FocusItem].id;
      {         taxcode := 0;
               discount := 0; }
             end;
        SaleListBox.AddItem(SaleItem, ManualEntryForm.EditQuantity.Value);
        DisplayMessage(Copy(SaleItem.name, 1, 19) + #10#13 + FormatFloat(CurrencyFormatString, SaleItem.saleprice));
        if not SaleListbox.isRefund then SaleStatusLabel.Text := 'Sale in progress';
        TotalButton.Enabled := SaleListBox.Count>0;
        ManualEntryForm.ManualEnterButton.Enabled := false;
        ManualEntryForm.EditFloat1.Value := 0;
        UpdateTotal;
      end;
end;

procedure TfposTerm.IncreaseSaleClick ( Sender: TObject ) ;
begin
  if TotalButton.Enabled then
    begin
      SaleListbox.AdjustQuantity(SaleListbox.FocusItem, 1);
      UpdateTotal;
    end;
end;

procedure TfposTerm.DecreaseSaleClick ( Sender: TObject ) ;
begin
  if TotalButton.Enabled then
    begin
      SaleListbox.AdjustQuantity(SaleListbox.FocusItem, -1);
      UpdateTotal;
    end;
end;

procedure TfposTerm.TotalButtonClick ( Sender: TObject ) ;
          procedure SetSaleStatusComplete;
          begin
           with SaleStatusLabel do
              begin
                TextColor := clBlack;
                if SaleListbox.isRefund
                   then Text := 'Refund complete'
                   else Text := 'Sale complete';
              end;
          end;
var
  Salemessage: String;
begin
  if SaleListbox.isRefund then
     begin
       TotalButton.Enabled := not ClientDB.RegisterSale(SaleListbox);
       if not TotalButton.Enabled then SetSaleStatusComplete;
       Salemessage := 'Refund total';
       SaleListbox.isRefund := TotalButton.Enabled;
     end
  else
     begin
       TotalButton.Enabled := not ClientDB.RegisterSale(SaleListbox);
       if not TotalButton.Enabled then SetSaleStatusComplete;
       Salemessage := 'Sale total';
     end;
  if not TotalButton.Enabled then
     begin
       ConnectPrinter('COM1');
       SerialPrinter.SendString(#27'='#2);  // Select display
       SerialPrinter.SendByte($0C);         // CLS
       SerialPrinter.Flush;

       SerialPrinter.SendString(Salemessage + #13#10);
       SerialPrinter.SendString(#156 + Copy(TotalLabel.Text, 3, 20));
       OpenDrawer;
       FreeAndNil(SerialPrinter);
     end;

  UpdateTotal;
end;

procedure TfposTerm.PaintLogo(Sender: TObject);
begin
  if assigned(Logo) then
  With TfpgPanel(Sender).Canvas do
       begin
         DrawImage(10, 10, Logo);
       end;
end;

procedure TfposTerm.UpdateTotal;
var
  salenum: Integer;
begin
  TotalLabel.Text := CurrencyString + #32 + FormatFloat(CurrencyFormatString, SaleListbox.SaleTotal);
  ItemsLabel.Text := IntToStr(SaleListbox.SaleCount) + ' items';
  if TotalButton.Enabled
     then salenum := ClientDB.SaleRef+1
     else salenum := ClientDB.SaleRef;
  SaleNumLabel.Text := '# ' + IntToStr(salenum);
  if SaleListbox.isRefund then
     begin
       //Show salestatus
     end
  else
     begin
       // Show Salestatus
     end;
    ReceiptButton.Enabled := not TotalButton.Enabled;
 end;

procedure TfposTerm.Keypress ( Sender: TObject; var KeyCode: word;
  var ShiftState: TShiftState; var Consumed: boolean ) ;
var
  ReportDB: TSqlite3Dataset;
  fontdesc: String;
  fontd: string;
  x: Integer;
  frm: TfpgFontSelectDialog;
begin
    {$IFDEF DEBUG}
//  writeln('KeyPress: ', KeyCode, #32, chr(KeyCode));
  {$ENDIF}
  if (KeyCode=67) and (ssCtrl in ShiftState) then
     begin
       freadingbarcode := false;
       // Add the item if record found
       if ClientDB.SearchForProduct(fbarcodebuffer, true)=1
          then AddSaleByBarcode
          else ShowMessage('Barcode not found');  // then focus manual barcode entry
       Consumed := true;
     end
  else if freadingbarcode then
     begin
       if (KeyCode>32) and (Keycode<128)
          then fbarcodebuffer := fbarcodebuffer + chr(KeyCode);
       Consumed := true;
     end
  else if (KeyCode=66) and (ssCtrl in ShiftState) then
     begin
       //TODO: move this code to FindItemForm
       //Focus input edit if on barcode entry page
       {if FindItemForm.BarcodePanel.Visible then
          if not BarcodeEntryEdit.Focused
             then BarcodeEntryEdit.SetFocus; }
       fbarcodebuffer := '';
       freadingbarcode := true;
       consumed := true;//consumed := not BarcodePanel.Visible;
     end;
  if KeyCode=keyF10 then
     begin
       EndShift;
     end;
  if KeyCode=keyF12 then
          begin
            ConnectPrinter('COM1');
            OpenDrawer;
            FreeAndNil(SerialPrinter);
          end;
  if (KeyCode=keyF3) and (ssShift in ShiftState) then
  begin
    fontdesc := Settings.ReadString('Terminal', 'Base font', FPG_DEFAULT_SANS);
    frm := TfpgFontSelectDialog.Create(nil);
 //   fontdesc := FastsaleButton.FontDesc;
    frm.SetFontDesc(FontDesc);
    if frm.ShowModal = mrOK then
    begin
      FontDesc := frm.GetFontDesc;
      fpgSetNamedFont('Label1', fontdesc);
      Settings.WriteString('Terminal', 'Base font', Copy(fontdesc, 1, Pos('-', fontdesc)-1));
      Settings.WriteInteger('Terminal', 'Base font size', frm.FontSize);
    end;
    frm.Free;

  end;
  {$IFDEF DEBUG}
  //writeln(fbarcodebuffer, #32, Length(fbarcodebuffer));
  {$ENDIF}
end;

procedure TfposTerm.HandleDisconnect ( aSocket: TObject ) ;
begin
  ConnectionStatusLabel.Text := 'Disconnected';
  fClockTimer.Enabled := true;
end;

procedure TfposTerm.HandleConnect ( aSocket: TObject ) ;
begin
  ConnectionStatusLabel.Text := 'Connected';
  fClockTimer.Enabled := true;
end;

procedure TfposTerm.AddSaleByBarcode( abarcode: Pchar=nil );
var
  SaleItem: TfpProduct;
begin
  if not TotalButton.Enabled then SaleListbox.ResetSale;

  with SaleItem do
       begin
         id := ClientDB.DataDB.FieldByName('productid').AsInteger;
         if abarcode<>nil then
            begin
              fbarcodebuffer := abarcode;
            end;
         barcode := ClientDB.DataDB.FieldByName('barcode').AsString;
         name := ClientDB.DataDB.FieldByName('name').AsString;
         if barcode[1]='2'
             then saleprice := StrToFloat(Copy(fbarcodebuffer, Length(fbarcodebuffer)-5, 5))/100
             else saleprice := ClientDB.DataDB.FieldByName('saleprice').AsFloat;
         taxcode := ClientDB.DataDB.FieldByName('taxcode').AsInteger;
         dept := ClientDB.DataDB.FieldByName('dept').AsInteger;
         discount := ClientDB.DataDB.FieldByName('discount').AsInteger;
       end;
  SaleListBox.AddItem(SaleItem, SetQuantityForm.EditQuantity.Value);
  DisplayMessage(Copy(SaleItem.name, 1, 19) + #10#13 + FormatFloat('0.00', SaleItem.saleprice));

  if not SaleListbox.isRefund then SaleStatusLabel.Text := 'Sale in progress';
  TotalButton.Enabled := SaleListBox.Count>0;
  UpdateTotal;
end;

procedure TfposTerm.AfterCreate;
var
  ImgData: TfpgResource;
  x: Integer;
begin
  {$IFDEF DEBUG}
  writeln('aftercreating');
  {$ENDIF}
   {%region 'Auto-generated GUI code' -fold}
  {@VFD_BODY_BEGIN: fposTerm}
  Name := 'fposTerm';
  SetPosition(0, 0, 1024, 768);
  WindowTitle := 'FirePOS Terminal';
  Hint := '';
  WindowPosition := wpUser;
  //OnResize := @OnFormResize;
  OnKeyPress := @Keypress;
  OnClose := @FormClose;
  //resize window and remove window decoration so that it fills the screen
  WindowAttributes := [waBorderless];
  //Width := fpgApplication.ScreenWidth;
  //Height := fpgApplication.ScreenHeight;
  { VertSplitter := TfpgSplitter.Create(Self);
  with VertSplitter do
  begin
  Name := 'VertSplitter';
  SetPosition(00, 292, 8, 520);
  Align := alRight;
  end;            }

  StatusPanel := TfpgPanel.Create(self);
  with StatusPanel do
  begin
    Name := 'StatusPanel';
    SetPosition(0, 744, 1024, 24);
    Align := alBottom;
    BorderStyle := bsDouble;
    FontDesc := '#Label1';
    Hint := '';
    Style := bsLowered;
    Text := '';
  end;

  ConnectionStatusLabel := TfpgLabel.Create(StatusPanel);
  with ConnectionStatusLabel do
  begin
    Name := 'ConnectionStatusLabel';
    SetPosition(8, 4, 144, 16);
    FontDesc := '#StatusLabel';
    Hint := '';
    Text := 'ConnectionStatusLabel';
  end;

  StaffNameLabel := TfpgLabel.Create(StatusPanel);
  with StaffNameLabel do
  begin
    Name := 'StaffNameLabel';
    SetPosition(368, 4, 164, 16);
    FontDesc := '#StatusLabel';
    Hint := '';
    Text := 'StaffNameLabel';
  end;

  TopPanel := TfpgPanel.Create(self);
  with TopPanel do
  begin
    Name := 'TopPanel';
    SetPosition(0, 0, 1024, 60);
    Align := alTop;
    FontDesc := '#Label1';
    Hint := '';
    Text := '';
  end;

  DateTimePanel := TfpgPanel.Create(TopPanel);
  with DateTimePanel do
  begin
    Name := 'DateTimePanel';
    SetPosition(770, 2, 252, 56);
    Align := alRight;
    FontDesc := '#Label1';
    Hint := '';
    Style := bsLowered;
    Text := '';
  end;

  DayLabel := TfpgLabel.Create(DateTimePanel);
  with DayLabel do
  begin
    Name := 'DayLabel';
    SetPosition(51, 8, 80, 16);
    Alignment := taCenter;
    FontDesc := '#Label1';
    Hint := '';
    Text := 'Saturday';
    Autosize := false;
  end;

  MonthLabel := TfpgLabel.Create(DateTimePanel);
  with MonthLabel do
  begin
    Name := 'MonthLabel';
    SetPosition(53, 28, 80, 16);
    Alignment := taCenter;
    FontDesc := '#Label1';
    Hint := '';
    Text := 'Dec 2011';
    Autosize := false;
  end;

  TimeLabel := TfpgLabel.Create(DateTimePanel);
  with TimeLabel do
  begin
    Name := 'TimeLabel';
    SetPosition(147, 8, 96, 40);
    Alignment := taCenter;
    FontDesc := 'FreeSans-24:antialias=true';
    Hint := '';
    Text := '15:55';
  end;

  DateLabel := TfpgLabel.Create(DateTimePanel);
  with DateLabel do
  begin
    Name := 'DateLabel';
    SetPosition(3, 8, 48, 44);
    Alignment := taCenter;
    FontDesc := 'FreeSans-24:antialias=true';
    Hint := '';
    Text := '31';
    Autosize := false;
  end;

  Bevel1 := TfpgBevel.Create(DateTimePanel);
  with Bevel1 do
  begin
    Name := 'Bevel1';
    SetPosition(136, 4, 2, 48);
    Hint := '';
  end;

  MainInputPanel := TfpgPanel.Create(self);
  with MainInputPanel do
  begin
    Name := 'MainInputPanel';
    SetPosition(242, 60, 782, 684);
    Align := alRight;
    BorderStyle := bsNone;
    FontDesc := '#Label1';
    Hint := '';
    Margin := 0;
    Text := 'MainInputPanel';
  end;

  LowerPanel := TfpgPanel.Create(MainInputPanel);
  with LowerPanel do
  begin
    Name := 'LowerPanel';
    SetPosition(2, 602, 778, 80);
    Align := alBottom;
    FontDesc := '#Label1';
    Hint := '';
    Text := '';
  end;

  TotalButton := TfpgButton.Create(LowerPanel);
  with TotalButton do
  begin
    Name := 'TotalButton';
    SetPosition(572, 4, 196, 72);
    Anchors := [anRight,anTop];
    Text := 'TOTAL';
    BackgroundColor := TfpgColor($32CD32);
    Enabled := False;
    FontDesc := 'Bitstream Charter-24:antialias=true';
    Hint := '';
    ImageName := '';
    TabOrder := 1;
    OnClick := @TotalButtonClick;
  end;

  ReceiptButton := TfpgButton.Create(LowerPanel);
  with ReceiptButton do
  begin
    Name := 'ReceiptButton';
    SetPosition(412, 8, 116, 65);
    Anchors := [anRight,anTop];
    Text := 'RECEIPT';
    Enabled := False;
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 2;
    OnClick := @ReceiptButtonClick;
  end;

  Panel6 := TfpgPanel.Create(MainInputPanel);
  with Panel6 do
  begin
    Name := 'Panel6';
    SetPosition(2, 2, 778, 600);
    Align := alClient;
    BorderStyle := bsNone;
    FontDesc := '#Label1';
    Hint := '';
    Margin := 0;
    Text := 'Panel6';
  end;

  SaleModePanel := TfpgPanel.Create(Panel6);
  with SaleModePanel do
  begin
    Name := 'SaleModePanel';
    SetPosition(640, 2, 136, 596);
    Align := alRight;
    BackgroundColor := TfpgColor($0000FF);
    BorderStyle := bsNone;
    FontDesc := '#Label1';
    Hint := '';
    LineSpace := 0;
    Margin := 0;
    Text := '';
  end;

  BarcodeSaleButton := TfpgButton.Create(SaleModePanel);
  with BarcodeSaleButton do
  begin
    Name := 'BarcodeSaleButton';
    SetPosition(6, 12, 124, 75);
    Text := 'FIND ITEM';
    AllowAllUp := True;
    BackgroundColor := TfpgColor($FF8C00);
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 3;
    OnClick := @ModeButtonClick;
  end;

  ManualsaleButton := TfpgButton.Create(SaleModePanel);
  with ManualsaleButton do
  begin
    Name := 'ManualsaleButton';
    SetPosition(6, 96, 124, 75);
    Text := 'ENTER PRICE';
    AllowAllUp := True;
    BackgroundColor := TfpgColor($FF8C00);
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 4;
    OnClick := @ModeButtonClick;
  end;

  MenuButton := TfpgButton.Create(SaleModePanel);
  with MenuButton do
  begin
    Name := 'MenuButton';
    SetPosition(6, 512, 124, 75);
    Anchors := [anLeft,anBottom];
    Text := 'MENU';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 5;
    OnClick := @MenuButtonClick;
  end;

  SaleInputPanel := TfpgPanel.Create(Panel6);
  with SaleInputPanel do
  begin
    Name := 'SaleInputPanel';
    SetPosition(2, 2, 638, 596);
    Anchors := [anLeft,anRight,anTop,anBottom];
    Align := alClient;
    FontDesc := '#Label1';
    Hint := '';
    Margin := 0;
    Text := 'SaleInputPanel';
  end;

  PageControl := TfpgPageControl.Create(SaleInputPanel);
  with PageControl do
  begin
    Name := 'PageControl';
    SetPosition(2, 2, 634, 592);
    Anchors := [anLeft,anRight,anTop,anBottom];
    Align := alClient;
    FixedTabWidth := 100;
    Hint := '';
    TabOrder := 1;
    TabPosition := tpLeft;
    //    BackgroundColor := TfpgColor($FFFFFF);
    FixedTabHeight := 60;
    OnResize := @ButtonPagesResize;
  end;

  SaleInfoPanel := TfpgPanel.Create(self);
  with SaleInfoPanel do
  begin
    Name := 'SaleInfoPanel';
    SetPosition(0, 60, 242, 684);
    Align := alClient;
    BorderStyle := bsNone;
    FontDesc := 'FreeSans-15:antialias=true';
    Hint := '';
    Text := 'SaleInfoPanel';
  end;

  SaleAdjustmentPanel := TfpgPanel.Create(SaleInfoPanel);
  with SaleAdjustmentPanel do
  begin
    Name := 'SaleAdjustmentPanel';
    SetPosition(2, 610, 238, 72);
    Align := alBottom;
    FontDesc := '#Label1';
    Hint := '';
    Text := '';
  end;

  IncreaseSaleButton := TfpgButton.Create(SaleAdjustmentPanel);
  with IncreaseSaleButton do
  begin
    Name := 'IncreaseSaleButton';
    SetPosition(2, 5, 60, 60);
    Text := '+';
    FontDesc := 'Liberation Sans-24:bold:antialias=true';
    Hint := 'Increase quantity of selected sale line';
    ImageName := '';
    TabOrder := 1;
    TextColor := TfpgColor($008000);
    OnClick:=@IncreaseSaleClick;
  end;

  DecreaseSaleButton := TfpgButton.Create(SaleAdjustmentPanel);
  with DecreaseSaleButton do
  begin
    Name := 'DecreaseSaleButton';
    SetPosition(66, 5, 60, 60);
    Text := '-';
    FontDesc := '#Label1';
    Hint := 'Reduce quantity of selected sale item';
    ImageName := '';
    TabOrder := 2;
    TextColor := TfpgColor($FF0000);
    OnClick:=@DecreaseSaleClick;
  end;

  SaleSummaryPanel := TfpgPanel.Create(SaleInfoPanel);
  with SaleSummaryPanel do
  begin
    Name := 'SaleSummaryPanel';
    SetPosition(2, 530, 238, 80);
    Align := alBottom;
    BackgroundColor := TfpgColor($FFFFFF);
    BorderStyle := bsNone;
    FontDesc := '#Label1';
    Hint := '';
    Text := ' ';
    OnClick := @DisplayTotal;
  end;

  TotalLabel := TfpgLabel.Create(SaleSummaryPanel);
  with TotalLabel do
  begin
    Name := 'TotalLabel';
    SetPosition(116, 8, 116, 28);
    Anchors := [anRight,anTop];
    Alignment := taRightJustify;
    BackgroundColor := TfpgColor($FFFFFF);
    FontDesc := '#LargeText';
    Hint := '';
    Text := '0.00';
    OnClick := @DisplayTotal;
  end;

  Label2 := TfpgLabel.Create(SaleSummaryPanel);
  with Label2 do
  begin
    Name := 'Label2';
    SetPosition(316, 12, 80, 16);
    Anchors := [anRight,anTop];
    Alignment := taRightJustify;
    BackgroundColor := TfpgColor($FFFFFF);
    FontDesc := 'Arial-12:antialias=true';
    Hint := '';
    Text := 'TOTAL';
  end;

  ItemsLabel := TfpgLabel.Create(SaleSummaryPanel);
  with ItemsLabel do
  begin
    Name := 'ItemsLabel';
    SetPosition(8, 8, 92, 24);
    BackgroundColor := TfpgColor($FFFFFF);
    FontDesc := '#Label1';
    Hint := '';
    Text := 'Items';
    Autosize := true;
  end;

  SaleStatusLabel := TfpgLabel.Create(SaleSummaryPanel);
  with SaleStatusLabel do
  begin
    Name := 'SaleStatusLabel';
    SetPosition(8, 60, 184, 16);
    BackgroundColor := TfpgColor($FFFFFF);
    FontDesc := 'Arial-12:antialias=true';
    Hint := '';
    Text := 'SaleStatusLabel';
    OnClick := @DisplayTotal;
  end;

  SaleNumLabel := TfpgLabel.Create(SaleSummaryPanel);
  with SaleNumLabel do
  begin
    Name := 'SaleNumLabel';
    SetPosition(8, 44, 132, 16);
    BackgroundColor := TfpgColor($FFFFFF);
    FontDesc := '#Label1';
    Hint := '';
    Text := 'SaleNumLabel';
    Autosize := true;
    OnClick := @DisplayTotal;
  end;

  SaleListbox := TfpgSaleListbox.Create(SaleInfoPanel);
  with SaleListbox do
  begin
    Name := 'SaleListbox';
    SetPosition(4, 4, 364, 468);
    Align:=alClient;
    FontDesc := 'Arial-12:antialias=true';
  end;

  Button1 := TfpgButton.Create(SaleModePanel);
  with Button1 do
  begin
    Name := 'Button1';
    SetPosition(6, 204, 124, 75);
    Text := 'SET QUANTITY';
    BackgroundColor := TfpgColor($FD8A00);
    FontDesc := '#Label1';
    Hint := '';
    ImageName := '';
    TabOrder := 4;
    OnClick := @SetSaleQuantity;
  end;

  QuantityLabel := TfpgLabel.Create(StatusPanel);
  with QuantityLabel do
  begin
    Name := 'QuantityLabel';
    SetPosition(216, 4, 100, 16);
    FontDesc := '#StatusLabel';
    Hint := '';
    Text := 'Qty: 1';
  end;

  {@VFD_BODY_END: fposTerm}
  {%endregion}
  ClientDB.OnStaffLogon := @StaffStatusChange;
  ClientDB.OnStaffLogout := @StaffStatusChange;
  ClientDB.OnResumeShift := @ResumeShift;

  SaleNumLabel.Text := '';
  SaleStatusLabel.Text := 'No sale';
  fClockTimer := TfpgTimer.Create(60000);
  with fClockTimer do
       begin
         Interval := 6000;
         OnTimer := @OnClockTimer;
//         Enabled := true;   // enabled after attempt to connect
       end;
  TopPanel.OnPaint := @PaintLogo;
  SetDateDay;
  SetupPages;
  RefreshDiscounts;
 fposClient.OnConnect := @HandleConnect;
 fposClient.OnDisConnect := @HandleDisconnect;
 if fposClient.Connection.Connected
    then HandleConnect(nil)
    else HandleDisconnect(nil);
  ImgData := LazarusResources.Find('firepos_logo_137x30');
  Logo := nil;
  if ImgData<>nil
     then Logo := CreateImage_BMP(Pointer(ImgData.Value), Length(ImgData.Value));
 if Assigned(Logo) then
    begin
      Logo.CreateMaskFromSample(0,0);
      Logo.UpdateImage;
    end;
end;

procedure TfposTerm.ModeButtonClick(Sender: TObject);
begin
 SaleModePanel.Enabled := false;
 if Sender=BarcodeSaleButton
                                                    then FindItemForm.ShowModal
 else if Sender=ManualsaleButton
                                                    then ManualEntryForm.ShowModal;
 SaleModePanel.Enabled := true;
end;

procedure TfposTerm.ReceiptButtonClick ( Sender: TObject ) ;
var
scale,rmargin,lmargin,x,r:integer;
newline:string;
substring : string;
begin
 ConnectPrinter('COM1');

 SerialPrinter.SendString(#27'='#1);  // Select printer
 SerialPrinter.Flush;
 SerialPrinter.SendString( #27#77 + #27#29#97#49 );  //set 17cpi, centre align
 PrintLogo(1);
 SerialPrinter.SendString(  #27#105#49#49 + 'Mallaig Heritage Centre' + #27#105#48#48 + #10);
 SerialPrinter.SendString( #27#69 + 'Station Road, Mallaig PH41 4PY' + #27#70 + #10);
 SerialPrinter.SendString( #27#69 + 'Tel. 01687 462085' + #27#70 + #10);
 SerialPrinter.SendString( #27#45#49 + 'www.mallaigheritage.org.uk' + #27#45#48 + #10#10);
 SerialPrinter.SendString( #27#29#97#48);  // Set left align
 newline := StringOfChar( #32, 17);
 AlignInString( newline, FormatDateTime('d mmm yyyy hh:mm', Now), taLeftJustify);
 AlignInString( newline, IntToStr(ClientDB.SaleRef), taRightJustify);
 SerialPrinter.SendString(#10 + newline + #10#10);
 SerialPrinter.SendString( #27#29#97#50 + #156 + #10);  // right align currency symbol
 SerialPrinter.SendString( #27#29#97#48);  // Set left align

 for x := 1 to SaleListbox.ItemCount do
      begin
        newline := StringOfChar( #32, 17);
        AlignInString(newline, TSaleLine(SaleListbox.Items.Objects[x-1]).Product.name, taLeftJustify);
        PrintReceiptLine( newline );
        newline := StringOfChar( #32, 17);
        AlignInString(newline, IntToStr(TSaleLine(SaleListbox.Items.Objects[x-1]).Quantity)
                        + FormatFloat( 'x  0.00', TSaleLine(SaleListbox.Items.Objects[x-1]).Product.saleprice ), taLeftJustify);
        AlignInString(newline,
              FormatFloat( CurrencyFormatString, TSaleLine(SaleListbox.Items.Objects[x-1]).Product.saleprice * TSaleLine(SaleListbox.Items.Objects[x-1]).Quantity)
               , taRightJustify);
        PrintReceiptLine( newline );
      end;
 for x := 0 to SaleListbox.Discounts.Count-1 do
     if SaleListbox.Discounts.Items[x].balance>0.0 then
      begin
        newline := StringOfChar( #32, 17);
        AlignInString(newline, SaleListbox.Discounts.Items[x].description, taLeftJustify);
        AlignInString(newline,
              '- ' + FormatFloat( CurrencyFormatString, SaleListbox.Discounts.Items[x].balance) , taRightJustify);
        PrintReceiptLine( newline );
      end;
 SerialPrinter.SendString( stringOfChar('-', 17) + #10 + #27#58);  // set 16 dot pitch
 PrintReceiptLine( #27#29#97#50  // set right align
                   + #27#69      // set emphasised
                   + 'TOTAL   ' + #156 + Copy(TotalLabel.Text, 3, 20)
                   + #27#70 // cancel emphasised
                   );

 SerialPrinter.SendString( #27#29#97#48 + #10#27#77 +       // set left align, 12 dot pitch
 'Thank You for helping Mallaig Heritage Centre' + #10 +
 'to preserve and interpret the history of ' + #10 +
 'West Lochaber.' + #10 +
 'Mallaig Heritage Centre is a community owned ' +#10 +
 'museum and a registered charity no. SC016510' +#27#70 + #10);
 SerialPrinter.SendString(#10#27#100#50); //cut
 SerialPrinter.Flush;

 FreeAndNil(SerialPrinter);
 {SerialPrinter.Free;
 SerialPrinter := nil;}
end;

procedure TfposTerm.BarcodeEnterClick ( Sender: TObject ) ;
var
  buffer: string;
begin
  buffer := FindItemForm.BarcodeEntryEdit.Text;
  if Length(buffer)>0 then
     AddSaleByBarcode(PChar(buffer));
end;

procedure TfposTerm.ResumeShift ( Sender: TObject ) ;
begin
  StaffNameLabel.Text := ClientDB.ShiftInfo.StaffName;
end;

procedure TfposTerm.StaffStatusChange ( Sender: TObject; SQL: string ) ;
begin
  StaffNameLabel.Text := ClientDB.ShiftInfo.StaffName;
  if Sender=nil
     then fposClient.SendShiftStatus(ClientDB.ShiftInfo.StaffID, fpmStaffLogon, SQL)
     else fposClient.SendShiftStatus(ClientDB.ShiftInfo.StaffID, fpmStaffLogoff, SQL);
  SaleListbox.ResetSale;
  TotalButton.Enabled := false;
  ItemsLabel.Text := '';
  SaleStatusLabel.Text := '';
  TotalLabel.Text := FormatFloat(CurrencyFormatString, 0);
  DisplayMessage(' ');
  SideBar.Hide;
  SaleListbox.isRefund := false;
end;

procedure TfposTerm.MenuButtonClick ( Sender: TObject ) ;
begin
  SideBar.AdjustHeight(GetScreenPos(MenuButton).Y + MenuButton.Height);
  SideBar.CancelButton.Enabled := TotalButton.Enabled;
  SideBar.ShowModal;
  SideBar.Hide;
end;

procedure TfposTerm.ButtonPagesResize ( Sender: TObject ) ;
var
  p: Integer;
begin
  {$IFDEF DEBUG}
  writeln('ButtonPagesResize');
  {$ENDIF}
  for p := 0 to PageControl.PageCount-1 do
     TProductPage(PageControl.Pages[p]).AlignButtons;
end;

procedure TfposTerm.FormClose ( Sender: TObject;
  var CloseAction: TCloseAction ) ;
begin
  ClientDB.DataDB.ExecuteDirect('UPDATE terminal SET lastsale=' + IntToStr(ClientDB.SaleRef));
end;

procedure TfposTerm.SetSaleQuantity ( Sender: TObject ) ;
var
  oldvalue: Integer;
begin
  oldvalue := SetQuantityForm.EditQuantity.Value;
  SetQuantityForm.EditQuantity.Value := 0;
  if SetQuantityForm.ShowModal<>mrOK
      then SetQuantityForm.EditQuantity.Value := oldvalue;
  QuantityLabel.Text := 'Qty: ' + SetQuantityForm.EditQuantity.Text;
end;

procedure TfposTerm.ResetSaleQuantity( value: integer=1 );
begin
  SetQuantityForm.EditQuantity.Value := value;
  QuantityLabel.Text := 'Qty: ' + IntToStr(value);
end;

procedure TfposTerm.RefreshDiscounts;
var
  Disc: TSqlite3Dataset;
  adiscount: TDiscountItem;
begin
  Disc := ClientDB.GetDiscounts;
  if Disc<>nil then
     begin
       SaleListbox.Discounts.Clear;
       while not Disc.EOF do
             begin
               adiscount.discountid := Disc.Fields[0].AsInteger;
               adiscount.description := disc.Fields[1].AsString;
               adiscount.discounttype := Disc.Fields[2].AsInteger;
               adiscount.starttime := Disc.Fields[3].AsFloat;
               adiscount.endtime := Disc.Fields[4].AsFloat;
               adiscount.triggerqty := Disc.Fields[5].AsInteger;
               adiscount.discount := disc.Fields[6].AsFloat;
               SaleListbox.Discounts.AddDiscount(adiscount);
               Disc.Next;
             end;
     end;
end;

function TfposTerm.GetScreenPos ( Widget: tfpgWidget) : TPoint;
var
  x: integer;
  y: integer;
begin
  x := 0;
  y := 0;
  while Widget <> Self do
        begin
          x := x + Widget.Left;
          y := y + Widget.Top;
          Widget := Widget.Parent;
        end;
  Result.X := x;
  Result.Y := y;
end;

procedure TfposTerm.DisplayMessage(msg: string);
begin
  ConnectPrinter('COM1');

  SerialPrinter.SendString(#27'='#2);  // Select display
  SerialPrinter.SendByte($0C);         // CLS
  SerialPrinter.Flush;

  SerialPrinter.SendString(msg);
  SerialPrinter.SendString(#27'='#1);  // Select printer
  SerialPrinter.Flush;

  FreeAndNil(SerialPrinter);
end;

procedure TfposTerm.DisplayTotal(Sender: TObject);
var
  msg: String;
begin
  msg := 'Sale total'+ #13#10#156 + Copy(TotalLabel.Text, 3, 20);
  DisplayMessage(msg);
end;

procedure TfposTerm.UpdateLock;
var
  lockfilename: String;
  timefile: file of TDateTime;
  thismoment : TDateTime;
begin
  thismoment := Now;
  lockfilename := ClientDB.ConfigDirectory + SHIFT_LOCK;
  AssignFile(timefile,lockfilename);
  Rewrite(timefile);
  write(timefile, thismoment);
  Closefile(timefile);
end;

procedure TfposTerm.EndShift;
begin
  if ClientDB.StaffLogout=mrOK then
          begin
            ConnectPrinter('COM1');
            OpenDrawer;
            FreeAndNil(SerialPrinter);
          end;
end;

procedure TfposTerm.RefundClick ( Sender: TObject ) ;
begin
  if not TotalButton.Enabled then
      begin
        SaleListbox.isRefund := true;
        SaleStatusLabel.Text := 'Processing refund';
        SaleStatusLabel.TextColor := clRed;
      end
  else ShowMessage('You must complete or cancel the current sale' + LineEnding + 'before processing a refund');
  SideBar.Hide;
end;

procedure TfposTerm.CancelSaleClick ( Sender: TObject ) ;
var
  M: TfpgMessageDialog;
begin
  M := TfpgMessageDialog.Create(nil);
  if M.Question('', 'Cancel this sale completely?')=mbYes then
     begin
       SaleListbox.ResetSale;
       TotalButton.Enabled := false;
       ItemsLabel.Text := '';
       SaleStatusLabel.Text := 'Sale cancelled';
       TotalLabel.Text := FormatFloat(CurrencyFormatString, 0);
       DisplayMessage('Sale cancelled');
       SideBar.Hide;
       SaleListbox.isRefund := false;
     end;
  M.Free;
end;

procedure TfposTerm.CreatePage ( pagetitle: string ) ;
var
  newpage: TProductPage;
begin
    newpage := TProductPage.Create(PageControl);
  with newpage do
  begin
    SetPosition(103, 3, 529, 518);
    Anchors := [anLeft,anRight,anTop,anBottom];
//    BackgroundColor := TfpgColor($B22222);
    Text := pagetitle;
    CreateButtons(4, 5, @ProductButtonClick);
  end;
end;

procedure TfposTerm.SetupPages;
var
  S: TStringList;
  p: Integer;
begin
  S := ClientDB.GetPages;
  for p := 0 to S.Count-1 do
      CreatePage(S[p]);
  S.Free;
  SetupButtons;
end;

procedure TfposTerm.SetupButtons;
var
  Btns: TSqlite3Dataset;
  aproduct: TfpProduct;
begin
  Btns := ClientDB.GetButtons;
  if Btns<>Nil then
     while not Btns.EOF do
     begin
       with TProductPage( PageControl.Pages[Btns.FieldByName('pagenum').AsInteger]).ButtonList[Btns.FieldByName('row').AsInteger, Btns.FieldByName('col').AsInteger] as TProductButton do
       begin
         Visible :=  Btns.FieldByName('visible').AsInteger=1;
         aProduct.id := Btns.FieldByName('itemid').AsInteger;
         aProduct.Barcode := Btns.FieldByName('barcode').AsString;
         Text := Btns.FieldByName('caption').AsString;
         aProduct.name := Text;
         aproduct.discount := Btns.FieldByName('discount').AsInteger;
         aProduct.saleprice := Btns.FieldByName('saleprice').AsFloat;
         aProduct.dept := Btns.FieldByName('dept').AsInteger;
         aProduct.taxcode := Btns.FieldByName('taxcode').AsInteger;
         Product := aproduct;
       end;
       Btns.Next;
     end;
end;


{ TProductPage }

procedure TProductPage.DeleteButtons;
var
  r: Integer;
  c: Integer;
begin
  for r := fRows-1 downto 0 do
    for c := fCols-1 downto 0 do
    if ButtonList[r][c]<>nil then ButtonList[r][c].Free;
  SetLength(ButtonList, 0, 0);
end;

procedure TProductPage.BeforeDestruction;
begin
  DeleteButtons;
  inherited BeforeDestruction;
end;

procedure TProductPage.CreateButtons(cols, rows: integer; ClickEvent: TNotifyEvent);
var
  r: Integer;
  c: Integer;
begin
  DeleteButtons;
  fCols := cols;
  fRows := rows;
  SetLength(ButtonList, fRows, fCols);
  for r := 0 to fRows-1 do
    for c := 0 to fCols-1 do
      begin
        ButtonList[r, c] := TProductButton.Create(Self);
        with ButtonList[r,c] as TProductButton do
             begin
               Parent := Self;
               Visible := false;
               OnClick := ClickEvent;
               FontDesc := '#Label1';
             end;
      end;
  AlignButtons;
end;

procedure TProductPage.AlignButtons;
var
  w: Integer;
  h: Integer;
  r: Integer;
  c: Integer;
begin
  w := ((Self.Width-(BUTTONMARGIN*2)) div fCols) - BUTTONMARGIN;
  h := ((Self.Height-(BUTTONMARGIN*2)) div fRows) - BUTTONMARGIN;
  for r := 0 to fRows-1 do
    for c := 0 to fCols-1 do
       begin
         ButtonList[r][c].SetPosition(BUTTONMARGIN + ((w+BUTTONMARGIN)*c),
                                      BUTTONMARGIN + ((h+BUTTONMARGIN)*r),
                                      w,
                                      h);
       end;
end;

end.
